#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>

#include <readconf.h>
#include <hostmap.h>

#include "communicator.h"

int main(void)
{
	pid_t pid;
	int proc_no, ret;
	int status, n;

	//process one, comunication from agent to client.
	proc_no = 1;
	pid = fork();
	if (pid == -1) {
		perror("fork()");
		exit(1);
	}
	if (pid == 0) {
		ret = cmt_proc(proc_no);

		exit(ret);
	}

	//process two, comunication form client to agent.
	proc_no = 2;
	pid = fork();
	if (pid == -1) {
		perror("fork()");
		exit(1);
	}
	if (pid == 0) {
		ret = cmt_proc(proc_no);

		exit(ret);
	}

	for (n = 0; n < proc_no; n++) {
		pid = wait(&status);
		if (pid < 0) {
			perror("wait()");
			exit(1);
		}
		if (!WIFEXITED(status) && !WIFSIGNALED(status)) {
			n--;
		}
	}

	exit(0);

}

/*交互子进程*/
static int cmt_proc(int proc_no)
//int main(void)
{
	int ssd, csd;
	struct sockaddr_in saddr, caddr;
	socklen_t clen;
	pid_t   child_pid;
	struct sigaction sa;
	struct msg_cmt_st *cmt;
	int cmt_size;
	int ret;

	read_host_conf();
	read_conf();

	sa.sa_handler = chld_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_NOCLDSTOP;

	ssd = socket(AF_INET, SOCK_STREAM, 0);
	if (ssd == -1) {
		perror("socket()");
		exit(1);
	}

	//int proc_no = 1;
	memset(&saddr, 0, sizeof(saddr));
	saddr.sin_family = AF_INET;
	if (proc_no == 1) {					//Agent to Client
		saddr.sin_port = htons(get_cmt_port());
	} else {						//Client to Agent
		saddr.sin_port = htons(get_conn_port());
	}
	saddr.sin_addr.s_addr = htonl(INADDR_ANY);
	ret = bind(ssd, (struct sockaddr *)&saddr, sizeof(saddr));
	if (ret == -1) {
		perror("bind()");
		exit(1);
	}

	ret = listen(ssd, 255);
	if (ret == -1) {
		perror("listen()");
		exit(1);
	}

	sigaction(SIGCHLD, &sa, NULL);

	cmt = NULL;
	cmt_size = 0;
        while (1) {
                clen = sizeof(caddr);
                csd = accept(ssd, (struct sockaddr *)&caddr, &clen);
                if (csd == -1) {
                        if (errno == EINTR) {
                                continue;
                        }
                        perror("accept()");
                        continue;
                }   
		printf("Accept here\n");
			ret = rcev_cmt(csd, &cmt, &cmt_size);
		printf("step1\n");
			if (ret == -1) {
                        	//free_cmt(&cmt);
				close(csd);
				printf("continue111\n");
				continue;
			}
			ret = send_cmt(&cmt, &cmt_size, proc_no);
		printf("step2\n");
			if (ret == -1) {
                        	//free_cmt(&cmt);
				close(csd);
				printf("continue222\n");
				continue;
			}

			close(csd);
			printf("child pid = %d closed\n", (int)getpid());
/*
                child_pid = fork();
		printf("fork():pid = %d\n", child_pid);
                if (child_pid == -1) {
                        perror("fork()");
                        continue;
                }   
                if (child_pid == 0) {
                        close(ssd);

			ret = rcev_cmt(csd, &cmt, &cmt_size);
			if (ret == -1) {
                        	//free_cmt(&cmt);
				close(csd);
				exit(1);
			}
			ret = send_cmt(&cmt, &cmt_size, proc_no);
			if (ret == -1) {
                        	//free_cmt(&cmt);
				close(csd);
				exit(1);
			}

                        free_cmt(&cmt);
			close(csd);
			printf("child pid = %d closed\n", (int)getpid());
                        exit(0);
                } else {
                        close(csd);
                }*/
        }

        free_cmt(&cmt);
	close(ssd);

	return 0;
}

/*释放结构体struct cmt_recv_st指针*/
static void free_cmt(struct msg_cmt_st **cmt)
{
	if (*recv != NULL) {
		free(*recv);
	}

	return;
}

/*子进程收僵尸信号处理函数*/
static void chld_handler(int s)
{
        while (waitpid(-1, NULL, WNOHANG)>0);

        return;
}

/*接收交互/命令信息*/
static int rcev_cmt(int sockfd, struct msg_cmt_st **cmt, int *cmt_size)
{
	void *retc;
	int ret, len, pos;

	if (*cmt_size < sizeof(**cmt))
	{
		*cmt_size = sizeof(**cmt);
	}
	retc = realloc(*cmt, *cmt_size);
	if (retc == NULL) {
		if (*cmt != NULL) {
			free(*cmt);
		}
		return -1;
	}
	*cmt = retc;

	len = sizeof(**cmt);
	pos = 0;
	while (len > 0) {
		ret = read(sockfd, *cmt + pos, len);
		if (ret == -1) {
			if (errno == EINTR) {
				continue;
			}
			perror("read");
			free(*cmt);
			return -1;
		}
		pos += ret;
		len -= ret;
	}

	if (*cmt_size < sizeof(**cmt) + ntohl((*cmt)->offset)) {
		*cmt_size = sizeof(**cmt) + ntohl((*cmt)->offset);
	}
	retc = realloc(*cmt, *cmt_size);
	if (retc == NULL) {
		if (*cmt != NULL) {
			free(*cmt);
		}
		return -1;
	}
	*cmt = retc;

	len = ntohl((*cmt)->offset);
	pos = 0;
	while (len > 0) {
		ret = read(sockfd, &(*cmt)->data[1] + pos, len);
		if (ret == -1) {
			if (errno == EINTR) {
				continue;
			}
			perror("read()");
			free(*cmt);
			return -1;
		}
		pos += ret;
		len -= ret;
	}

	return 0;
}

/*转发交互/命令信息*/
static int send_cmt(struct msg_cmt_st **cmt, int *cmt_size, int proc_no)
{
	int sockfd;
	struct sockaddr_in saddr;
	struct host_info hinfo;
	int ret, pos, len;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd == -1) {
		perror("socket()");
		return -1;
	}

	get_hostinfo((*cmt)->host_map, &hinfo);

	memset(&saddr, 0, sizeof(saddr));
	saddr.sin_family = AF_INET;
	if (proc_no == 1) {						//Agent to Client
		saddr.sin_port = htons(get_conn_port());
	} else {							//Client to Agent
		saddr.sin_port = htons(get_cmt_port());
	}
	inet_pton(AF_INET, hinfo.ipaddr, &saddr.sin_addr);
printf("conn IP=%s\n", hinfo.ipaddr);
printf("conn PORT=%d\n", (int)ntohs(saddr.sin_port));

	ret = connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
	if (ret == -1) {
		perror("connect()");
		return -1;
	}

	len = sizeof(**cmt) + ntohl((*cmt)->offset);
printf("struct len = %d\n", len);
	pos = 0;
	while (len > 0) {
		ret = write(sockfd, *cmt + pos, len);
		if (ret == -1) {
			if (errno == EINTR) {
				continue;
			}
			perror("write()");
			free(*cmt);
			return -1;
		}
	}

	return 0;
}

